package captcha

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/wenlng/go-captcha-assets/resources/images"
	"github.com/wenlng/go-captcha-assets/resources/tiles"
	"github.com/wenlng/go-captcha/v2/slide"
	"product/authorization/serve/internal/svc"
	"product/authorization/serve/internal/types"
	"product/common/encryption"

	"github.com/zeromicro/go-zero/core/logx"
)

type CreateSlideCaptchaLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

// 生成滑动验证码
func NewCreateSlideCaptchaLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateSlideCaptchaLogic {
	return &CreateSlideCaptchaLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *CreateSlideCaptchaLogic) CreateSlideCaptcha() (resp *types.SlideCaptchaResp, err error) {
	builder, err := initSlideCaptcha()
	if err != nil {
		resp.Ok = false
		return resp, err
	}
	captcha, err := builder.Generate()
	if err != nil {
		resp.Ok = false
		return resp, err
	}
	captchaData := captcha.GetData()
	if captchaData == nil {
		resp.Ok = false
		return resp, errors.New("验证码生成失败")
	}
	var imageBase64, thumbBase64 string
	imageBase64, err = captcha.GetMasterImage().ToBase64()
	if err != nil {
		resp.Ok = false
		return resp, errors.New("图片生成失败")
	}
	thumbBase64, err = captcha.GetTileImage().ToBase64()
	if err != nil {
		resp.Ok = false
		return resp, errors.New("缩略图生成失败")
	}
	dotsByte, _ := json.Marshal(captchaData)
	key := encryption.Md5ByBytes(dotsByte)
	_ = l.svcCtx.Redis.SetexCtx(l.ctx, key, string(dotsByte), 60)
	resp.Ok = true
	resp.CaptchaKey = key
	resp.CaptchaBase64Image = imageBase64
	resp.CaptchCheckBase64Image = thumbBase64
	resp.CaptchCheckWidth = captchaData.Width
	resp.CaptchCheckHeight = captchaData.Height
	resp.CaptchCheckX = captchaData.X
	resp.CaptchCheckY = captchaData.Y

	return resp, nil
}

// 初始化滑动验证码
func initSlideCaptcha() (slide.Captcha, error) {
	slideBuilder := slide.NewBuilder(slide.WithEnableGraphVerticalRandom(true))
	imgs, err := images.GetImages()
	if err != nil {
		return nil, err
	}

	graphs, err := tiles.GetTiles()
	if err != nil {
		return nil, err
	}

	var newGraphs = make([]*slide.GraphImage, 0, len(graphs))
	for _, graph := range graphs {
		newGraphs = append(newGraphs, &slide.GraphImage{
			MaskImage:    graph.MaskImage,
			OverlayImage: graph.OverlayImage,
			ShadowImage:  graph.ShadowImage,
		})
	}

	slideBuilder.SetResources(slide.WithGraphImages(newGraphs), slide.WithBackgrounds(imgs))
	return slideBuilder.Make(), nil
}
